package com.wg.core.lock;

import com.wg.core.func.Action;
import com.wg.core.func.Func;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 增强型可重入锁工具类
 *
 * <p>提供更安全、更灵活的锁操作，支持超时控制、中断响应和锁状态查询</p>
 *
 * @author 少爷123
 */
public class SimpleLock {
    private final ReentrantLock lock;

    /**
     * 创建非公平锁实例
     */
    public SimpleLock() {
        this(false);
    }

    /**
     * 创建指定公平策略的锁实例
     *
     * @param fair true表示公平锁，false表示非公平锁
     */
    public SimpleLock(boolean fair) {
        this.lock = new ReentrantLock(fair);
    }

    /**
     * 执行无返回值的同步操作
     *
     * @param action 要执行的操作
     * @throws NullPointerException 如果action为null
     */
    public void execute(Action action) {
        if (action == null) {
            throw new NullPointerException("Action cannot be null");
        }

        lock.lock();
        try {
            action.doSomething();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 执行有返回值的同步操作
     *
     * @param action 要执行的操作
     * @param <T>    返回值类型
     * @return 操作执行结果
     * @throws NullPointerException 如果action为null
     */
    public <T> T execute(Func<T> action) {
        if (action == null) {
            throw new NullPointerException("Func cannot be null");
        }

        lock.lock();
        try {
            return action.doSomething();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 尝试获取锁并执行操作（支持超时）
     *
     * @param timeout 超时时间
     * @param unit    时间单位
     * @param action  要执行的操作
     * @return true表示成功获取锁并执行，false表示超时
     * @throws InterruptedException 如果线程被中断
     * @throws NullPointerException 如果action为null
     */
    public boolean tryExecute(long timeout, TimeUnit unit, Action action) throws InterruptedException {
        if (action == null) {
            throw new NullPointerException("Action cannot be null");
        }

        if (lock.tryLock(timeout, unit)) {
            try {
                action.doSomething();
                return true;
            } finally {
                lock.unlock();
            }
        }
        return false;
    }

    /**
     * 尝试获取锁并执行操作（支持超时和返回值）
     *
     * @param timeout 超时时间
     * @param unit    时间单位
     * @param action  要执行的操作
     * @param <T>     返回值类型
     * @return 操作执行结果，如果超时返回null
     * @throws InterruptedException 如果线程被中断
     * @throws NullPointerException 如果action为null
     */
    public <T> T tryExecute(long timeout, TimeUnit unit, Func<T> action)
            throws InterruptedException {
        if (action == null) {
            throw new NullPointerException("Func cannot be null");
        }

        if (lock.tryLock(timeout, unit)) {
            try {
                return action.doSomething();
            } finally {
                lock.unlock();
            }
        }
        return null;
    }

    /**
     * 执行可中断的同步操作
     *
     * @param action 要执行的操作
     * @throws InterruptedException 如果线程被中断
     * @throws NullPointerException 如果action为null
     */
    public void executeInterruptibly(Action action) throws InterruptedException {
        if (action == null) {
            throw new NullPointerException("Action cannot be null");
        }

        lock.lockInterruptibly();
        try {
            action.doSomething();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 执行可中断的同步操作（带返回值）
     *
     * @param action 要执行的操作
     * @param <T>    返回值类型
     * @return 操作执行结果
     * @throws InterruptedException 如果线程被中断
     * @throws NullPointerException 如果action为null
     */
    public <T> T executeInterruptibly(Func<T> action) throws InterruptedException {
        if (action == null) {
            throw new NullPointerException("Func cannot be null");
        }

        lock.lockInterruptibly();
        try {
            return action.doSomething();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 检查锁是否被当前线程持有
     *
     * @return true表示锁被当前线程持有
     */
    public boolean isHeldByCurrentThread() {
        return lock.isHeldByCurrentThread();
    }

    /**
     * 检查锁是否被任何线程持有
     *
     * @return true表示锁已被获取
     */
    public boolean isLocked() {
        return lock.isLocked();
    }

    /**
     * 获取等待获取此锁的线程数估计值
     *
     * @return 等待线程数
     */
    public int getQueueLength() {
        return lock.getQueueLength();
    }
}